namespace DotNetNuke.Services.Cache.FileBasedCachingProvider
{
    using DotNetNuke.Common;
    using DotNetNuke.Common.Utilities;
    using DotNetNuke.Framework.Providers;
    using DotNetNuke.Services.Cache;

    using System;
    using System.Collections;
    using System.IO;
    using System.Runtime.CompilerServices;
    using System.Text;
    using System.Web;
    using System.Web.Caching;
    using System.Xml.Serialization;

    public class FBCachingProvider : CachingProvider
    {
        private static Cache _objCache;
        private ProviderConfiguration _providerConfiguration = ProviderConfiguration.GetProviderConfiguration("caching");
        internal const string CacheFileExtension = ".resources";
        internal static string CachingDirectory = (DotNetNuke.Common.Globals.HostMapPath + @"Cache\");
        private const string ProviderType = "caching";

        public override object Add(string Key, object Value, CacheDependency Dependencies, DateTime AbsoluteExpiration, TimeSpan SlidingExpiration, CacheItemPriority Priority, CacheItemRemovedCallback OnRemoveCallback)
        {
            return objCache.Add(Key, (Value), Dependencies, AbsoluteExpiration, SlidingExpiration, Priority, OnRemoveCallback);
        }

        private static void CreateCacheFile(string FileName)
        {
            if (!File.Exists(FileName))
            {
                StreamWriter s = File.CreateText(FileName);
                if (s != null)
                {
                    s.Close();
                }
            }
        }

        private static void CreateCacheFile(string FileName, object ObjectToPersist)
        {
            string str = XmlUtils.Serialize((ObjectToPersist));
            if (!File.Exists(FileName))
            {
                StreamWriter s = File.CreateText(FileName);
                s.Write(str);
                if (s != null)
                {
                    s.Close();
                }
            }
        }

        private static void DeleteCacheFile(string FileName)
        {
            if (File.Exists(FileName))
            {
                File.Delete(FileName);
            }
        }

        public override IDictionaryEnumerator GetEnumerator()
        {
            return objCache.GetEnumerator();
        }

        private static string GetFileName(string FileName)
        {
            string FinalFileName = Convert.ToBase64String(Encoding.ASCII.GetBytes(FileName));
            if (FinalFileName.IndexOf("/") > -1)
            {
                FinalFileName = FinalFileName.Replace("/", "-");
            }
            return (CachingDirectory + FinalFileName + ".resources");
        }

        public override object GetItem(string CacheKey)
        {
            object obj = (objCache[CacheKey]);
            if (obj != null)
            {
                return objCache[CacheKey];
            }
            return obj;
        }

        public override object GetPersistentCacheItem(string CacheKey, Type objType)
        {
            object obj = (objCache[CacheKey]);
            if (obj != null)
            {
                return objCache[CacheKey];
            }
            if (DataCache.CachePersistenceEnabled)
            {
                string f = GetFileName(CacheKey);
                if (File.Exists(f))
                {
                    Stream objStream = File.OpenRead(f);
                    XmlSerializer serializer = new XmlSerializer(objType);
                    TextReader tr = new StreamReader(objStream);
                    obj = (serializer.Deserialize(tr));
                    tr.Close();
                    this.Insert(CacheKey, (obj), true);
                }
            }
            return obj;
        }

        public override void Insert(string CacheKey, object objObject, bool PersistAppRestart)
        {
            if (PersistAppRestart)
            {
                this.Remove(CacheKey);
            }
            string f = GetFileName(CacheKey);
            CacheDependency d = new CacheDependency(f);
            if (PersistAppRestart & DataCache.CachePersistenceEnabled)
            {
                CreateCacheFile(f, (objObject));
            }
            else if (DotNetNuke.Common.Globals.WebFarmEnabled)
            {
                CreateCacheFile(f);
            }
            else
            {
                d = null;
            }
            objCache.Insert(CacheKey, (objObject), d);
        }

        public override void Insert(string CacheKey, object objObject, CacheDependency objDependency, bool PersistAppRestart)
        {
            if (PersistAppRestart)
            {
                this.Remove(CacheKey);
            }
            string[] f = new string[] { GetFileName(CacheKey) };
            CacheDependency d = new CacheDependency(f, null, objDependency);
            if (PersistAppRestart & DataCache.CachePersistenceEnabled)
            {
                CreateCacheFile(f[0], (objObject));
            }
            else if (DotNetNuke.Common.Globals.WebFarmEnabled)
            {
                CreateCacheFile(f[0]);
            }
            else
            {
                d = objDependency;
            }
            objCache.Insert(CacheKey, (objObject), d);
        }

        public override void Insert(string CacheKey, object objObject, CacheDependency objDependency, DateTime AbsoluteExpiration, TimeSpan SlidingExpiration, bool PersistAppRestart)
        {
            if (PersistAppRestart)
            {
                this.Remove(CacheKey);
            }
            string[] f = new string[] { GetFileName(CacheKey) };
            CacheDependency d = new CacheDependency(f, null, objDependency);
            if (PersistAppRestart & DataCache.CachePersistenceEnabled)
            {
                CreateCacheFile(f[0], (objObject));
            }
            else if (DotNetNuke.Common.Globals.WebFarmEnabled)
            {
                CreateCacheFile(f[0]);
            }
            else
            {
                d = objDependency;
            }
            objCache.Insert(CacheKey, (objObject), d, AbsoluteExpiration, SlidingExpiration);
        }

        public override void Insert(string CacheKey, object objObject, CacheDependency objDependency, DateTime AbsoluteExpiration, TimeSpan SlidingExpiration, CacheItemPriority Priority, CacheItemRemovedCallback OnRemoveCallback, bool PersistAppRestart)
        {
            if (PersistAppRestart)
            {
                this.Remove(CacheKey);
            }
            string[] f = new string[] { GetFileName(CacheKey) };
            CacheDependency d = new CacheDependency(f, null, objDependency);
            if (PersistAppRestart & DataCache.CachePersistenceEnabled)
            {
                CreateCacheFile(f[0], (objObject));
            }
            else if (DotNetNuke.Common.Globals.WebFarmEnabled)
            {
                CreateCacheFile(f[0]);
            }
            else
            {
                d = objDependency;
            }
            objCache.Insert(CacheKey, (objObject), d, AbsoluteExpiration, SlidingExpiration, Priority, OnRemoveCallback);
        }

        public override string PurgeCache()
        {
            string[] f = Directory.GetFiles(CachingDirectory);
            int TotalFiles = f.Length;
            int PurgedFiles = this.PurgeCacheFiles(f);
            return string.Format("Purged " + PurgedFiles.ToString() + " of " + TotalFiles.ToString() + " cache synchronization files.", new object[0]);
        }

        private int PurgeCacheFiles(string[] strFiles)
        {
            int PurgedFiles = 0;
            int refIntHelperL0 = strFiles.Length - 1;
            for (int i = 0; i <= refIntHelperL0; i++)
            {
                TimeSpan refStructHelperS0 = new TimeSpan(2, 0, 0);
                if (DateTime.Compare(File.GetLastWriteTime(strFiles[i]), DateTime.Now.Subtract(refStructHelperS0)) < 0)
                {
                    string strFileName = strFiles[i].Substring(strFiles[i].LastIndexOf(@"\"));
                    if (DataCache.GetCache(strFileName.Substring(0, strFileName.Length - ".resources".Length)) == null)
                    {
                        File.Delete(strFiles[i]);
                        PurgedFiles++;
                    }
                }
            }
            return PurgedFiles;
        }

        public override void Remove(string CacheKey)
        {
            if (objCache[CacheKey] != null)
            {
                objCache.Remove(CacheKey);
                string f = GetFileName(CacheKey);
                if (DotNetNuke.Common.Globals.WebFarmEnabled)
                {
                    DeleteCacheFile(f);
                }
            }
        }

        public override void RemovePersistentCacheItem(string CacheKey)
        {
            if (objCache[CacheKey] != null)
            {
                objCache.Remove(CacheKey);
                if (DataCache.CachePersistenceEnabled)
                {
                    DeleteCacheFile(GetFileName(CacheKey));
                }
            }
        }

        private static Cache objCache
        {
            get
            {
                if (_objCache == null)
                {
                    _objCache = HttpRuntime.Cache;
                }
                return _objCache;
            }
        }
    }
}

